package com.wb.adutils

import android.app.Activity
import android.content.Context
import android.content.ContextWrapper
import android.text.TextUtils
import android.view.View
import android.view.ViewGroup
import androidx.constraintlayout.widget.ConstraintLayout
import com.bytedance.msdk.api.v2.GMAdConstant
import com.bytedance.msdk.api.v2.GMDislikeCallback
import com.bytedance.msdk.api.v2.GMMediationAdSdk
import com.bytedance.msdk.api.v2.GMSettingConfigCallback
import com.bytedance.msdk.api.v2.ad.nativeAd.GMNativeAd
import com.bytedance.msdk.api.v2.ad.nativeAd.GMNativeExpressAdListener
import com.bytedance.sdk.openadsdk.TTAdDislike
import com.bytedance.sdk.openadsdk.TTNativeExpressAd
import com.wb.adutils.AdUtils
import com.wb.adutils.callback.OnLoadAdListener
import com.wb.adutils.db.AdEntity
import com.wb.adutils.db.AdRoomUtils
import com.wb.adutils.tools.AdConstants
import com.wb.adutils.tools.LogC
import com.wb.adutils.tools.RxUtils
import io.reactivex.disposables.Disposable
import java.lang.ref.WeakReference
import java.util.*


abstract class AdBaseLoader(private val adEntity: AdEntity?) {

    protected var count: Int = 1
    protected var width: Int = 0
    protected var height: Int = 0
    protected var timeout: Int = 5
    protected var isAdLoadSuccess = false
    protected var listener: OnLoadAdListener? = null
    protected var timeoutDisposable: Disposable? = null
    protected var orientation: Int = GMAdConstant.VERTICAL
    private var activityWeakReference: WeakReference<Activity>? = null

    /**
     * 加载广告
     */
    fun loadAd(activity: Activity, template: Int, width: Int = 0, height: Int = 0, count: Int = 1, orientation: Int = GMAdConstant.VERTICAL, callback: OnLoadAdListener){
        try {
            if (activity.isFinishing || activity.isDestroyed) {
                release()
                return
            }
            // 当前广告的名字
            val adName = AdUtils.getNameByTemplate(template)
            // 获取广告
            if (adEntity == null || TextUtils.isEmpty(adEntity.adUnit)){
                LogC.e("$adName 没有配置广告...")
                callback.onAdComplete(true)
                return
            }

            // 判断时间间隔
            if (System.currentTimeMillis() - adEntity.showTime < adEntity.adInterval * 1000L) {
                LogC.e("$adName 在免广告时间范围内，不加载广告...")
                callback.onAdComplete(true)
                return
            }

            // template == AD_TEMPLATE_VIDEO 且第一次加载，屏蔽广告
            if (template == AdConstants.AD_TEMPLATE_VIDEO && AdUtils.isFirstLoadAd(activity)) {
                LogC.e("$adName 第一次加载，不显示广告...")
                callback.onAdComplete(true)
                return
            }

            // 下载广告且达到每日最大下载次数
            if (template == AdConstants.AD_TEMPLATE_DOWNLOAD) {
                val calendar = Calendar.getInstance()
                // 今天
                val today = calendar.get(Calendar.DAY_OF_YEAR)
                // 上次展示的时间
                calendar.time = Date(adEntity.showTime)
                //获得今天是本月的第几天，两种写法
                val lastShowDay = calendar.get(Calendar.DAY_OF_YEAR)
                // 当天
                if (today == lastShowDay) {
                    if (adEntity.dayDownloadCount >= adEntity.downloadDefaultCount) { // 达到每天的最大加载次数
                        LogC.e("$adName 达到每天的最大加载次数...")
                        callback.onAdLoadFail(AdConstants.AD_ERROR_CODE_MAX_REQUEST)
                        return
                    }
                } else { // 重置播放次数
                    LogC.e("$adName 次日广告请求书清零...")
                    adEntity.dayDownloadCount = 0
                    // 更新下载次数
                    updateAdEntity()
                }
            }
            this.count = count
            this.width = width
            this.height = height
            this.orientation = orientation
            listener = callback
            timeout = adEntity.timeout
            activityWeakReference = WeakReference(activity)
            if (AdUtils.isDebugModel()) {
                LogC.e("${AdUtils.getNameByTemplate(template)}广告id -> " + adEntity.adUnit)
            }
            // 准备加载广告
            /**
             * 判断当前是否存在config 配置 ，如果存在直接加载广告 ，如果不存在则注册config加载回调
             */
            if (adEntity.advertiser == 1) {
                if (GMMediationAdSdk.configLoadSuccess()) {
                    LogC.e("$adName 当前config配置存在，直接加载广告")
                    checkTimeout()
                    excLoadAd(activity)
                } else {
                    LogC.e("$adName 当前config配置不存在，正在请求config配置....")
                    GMMediationAdSdk.registerConfigCallback(mSettingConfigCallback) //不能使用内部类，否则在ondestory中无法移除该回调
                }
            } else {
                checkTimeout()
                excLoadAd(activity)
            }
        } catch (e: Exception) {
            e.printStackTrace()
            LogC.e("加载广告，出现异常...")
            callback.onAdLoadFail(AdConstants.AD_ERROR_CODE_EXCEPTION)
        }

    }

    // 真正执行加载广告
    protected abstract fun excLoadAd(activity: Activity)

    open fun onResume() {}

    open fun onPause() {}

    /**
     * 显示广告
     */
    abstract fun showAd(adRoot: ViewGroup? = null)



    open fun release(){
        listener = null
        isAdLoadSuccess = false
        timeoutDisposable?.dispose()
        timeoutDisposable = null
        //注销config回调
        GMMediationAdSdk.unregisterConfigCallback(mSettingConfigCallback)
    }


    protected open fun excAdLoadFail(errorCode: Int){
        if (timeoutDisposable?.isDisposed == true) { // 已超时
            return
        }
        // 停止守护线程
        timeoutDisposable?.dispose()
        listener?.onAdLoadFail(errorCode)
        release()
    }

    protected fun getActivity(): Activity? {
        val activity = activityWeakReference?.get()
        if (activity == null || activity.isFinishing || activity.isDestroyed) return null
        return activity
    }

    fun isAdLoaded(): Boolean {
        return isAdLoadSuccess
    }

    fun showAdWithListener(context: Context, nativeAd: Any, callback: OnLoadAdListener){
        if (nativeAd is GMNativeAd) {
            loadGMAd(context, nativeAd, callback)
        } else  if (nativeAd is TTNativeExpressAd) {
            loadPangleAd(context, nativeAd, callback)
        }
    }

    private fun loadGMAd(context: Context, nativeAd: GMNativeAd, callback: OnLoadAdListener) {
        nativeAd.setNativeAdListener(object : GMNativeExpressAdListener {
            override fun onAdClick() {
                callback.onAdClicked()
            }

            override fun onAdShow() {
                callback.onAdDisplay()
            }

            override fun onRenderFail(p0: View?, p1: String?, p2: Int) {
                callback.onAdLoadFail(p2)
            }

            override fun onRenderSuccess(p0: Float, p1: Float) {
                callback.onAdLoaded(nativeAd.expressView)
            }

        })

        //使用默认模板中默认dislike弹出样式
        nativeAd.setDislikeCallback(findActivity(context), object : GMDislikeCallback {
            override fun onShow() {}
            override fun onSelected(value: Int, enforce: String?) {
            }

            override fun onCancel() { // 无法关闭
                callback.onAdLoadFail(AdConstants.AD_ERROR_CODE_USER_CANCEL)
            }

            override fun onRefuse() {
            }
        })
        // 渲染广告
        nativeAd.render()
    }


    private fun loadPangleAd(context: Context, nativeAd: TTNativeExpressAd, callback: OnLoadAdListener){
        nativeAd.setExpressInteractionListener(object : TTNativeExpressAd.ExpressAdInteractionListener {
            override fun onAdClicked(p0: View?, p1: Int) {
                callback.onAdClicked()
            }

            override fun onAdShow(p0: View?, p1: Int) {
                callback.onAdDisplay()
            }

            override fun onRenderFail(p0: View?, p1: String?, p2: Int) {
                callback.onAdLoadFail(p2)
            }

            override fun onRenderSuccess(p0: View?, p1: Float, p2: Float) {
                callback.onAdLoaded(p0)
            }
        })
        val activity = findActivity(context)
        //使用默认模板中默认dislike弹出样式
        nativeAd.setDislikeCallback(activity, object : TTAdDislike.DislikeInteractionCallback {
            override fun onShow() {}
            override fun onCancel() {}
            override fun onSelected(position: Int, value: String, enforce: Boolean) {
                callback.onAdLoadFail(AdConstants.AD_ERROR_CODE_USER_CANCEL)
            }
        })
        nativeAd.render()
    }

    /**
     * 更新广告显示时间
     */
    fun updateAdShowTime(){
        if (adEntity == null) return
        // 更新广告展示时间
        RxUtils.doObservable<Int> {
            val dao = AdRoomUtils.getInstance()?.adDao()
            if (dao == null) {
                it.onComplete()
                return@doObservable
            }
            adEntity.showTime = System.currentTimeMillis()
            dao.update(adEntity)
            return@doObservable
        }
    }

    private fun updateAdEntity(){
        if (adEntity == null) return
        RxUtils.doObservable<Int> {
            val dao = AdRoomUtils.getInstance()?.adDao()
            if (dao == null) {
                it.onComplete()
                return@doObservable
            }
            dao.update(adEntity)
            return@doObservable
        }
    }

    /**
     * config回调
     */
    private val mSettingConfigCallback = GMSettingConfigCallback {
        val activity = getActivity()
        if (activity == null) {
            listener?.onAdLoadFail(AdConstants.AD_ERROR_CODE_ACTIVITY_IS_NULL)
            release()
            return@GMSettingConfigCallback
        }
        checkTimeout()
        excLoadAd(activity) //执行广告加载
    }


    protected fun findActivity(context: Context?): Activity? {
        if (context == null) return null
        if (context is Activity) {
            return context
        }
        return if (context is ContextWrapper) {
            findActivity(context.baseContext)
        } else {
            null
        }
    }

    /**
     * 广告的守护线程
     */
    private fun checkTimeout(){
        timeoutDisposable?.dispose()
        val delayTime = timeout
        if (delayTime <= 0) return
        timeoutDisposable = RxUtils.timer( delayTime * 1000L) {
            LogC.e("${AdUtils.getNameByTemplate(adEntity?.adTemplate?:AdConstants.AD_TEMPLATE_EXIT)}广告加载超时...")
            timeoutDisposable?.dispose()
            isAdLoadSuccess = false
            listener?.onAdLoadFail(AdConstants.AD_ERROR_CODE_TIMEOUT)
            listener = null
            //注销config回调
            GMMediationAdSdk.unregisterConfigCallback(mSettingConfigCallback)
        }
    }


}